package com.franklin.ideaplugin.mybatisrunner.runner;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.franklin.ideaplugin.api.utils.DocumentUtils;
import com.franklin.ideaplugin.api.utils.EditorUtils;
import com.franklin.ideaplugin.mybatisrunner.notification.PluginNotifier;
import com.franklin.ideaplugin.mybatisrunner.psi.MybatisPsiElement;
import com.intellij.database.console.JdbcConsole;
import com.intellij.database.model.DasNamed;
import com.intellij.database.psi.DbDataSource;
import com.intellij.database.psi.DbPsiFacade;
import com.intellij.database.settings.DatabaseSettings;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.sql.script.SqlScriptModel;
import org.apache.commons.io.FileUtils;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Ye Junhui
 * @since 2024/2/21
 */
public class DatabaseToolRunner {

    protected final Project project;

    private final MybatisPsiElement mybatisPsiElement;

    private JdbcConsole jdbcConsole;

    private Editor editor;

    public DatabaseToolRunner(MybatisPsiElement mybatisPsiElement) {
        this.mybatisPsiElement = mybatisPsiElement;
        this.project = mybatisPsiElement.getProject();
        EditorFactory editorFactory = EditorFactory.getInstance();
        Document document = editorFactory.createDocument("");
        editor = editorFactory.createEditor(document);
        EditorUtils.initEditor(editor);
//        checkJdbcConsoleActive("");
    }

    public void executeSql(String sql){
//        PluginNotifier.notifyInfo(project,"See execute sql in service panel");
//        if (Objects.isNull(jdbcConsole)){
            executeSqlWithChoosing(sql);
//        }else {
//            runSql(sql);
//        }
    }

    public void executeSqlWithChoosing(String sql){
        DbPsiFacade dbPsiFacade = DbPsiFacade.getInstance(project);
        List<DbDataSource> dataSources = dbPsiFacade.getDataSources();

        List<String> dataSourceNames = dataSources.stream()
                .map(DasNamed::getName)
                .collect(Collectors.toList());
        List<Icon> iconList = dataSources.stream()
                .map(DbDataSource::getIcon)
                .collect(Collectors.toList());
        JBPopupFactory jbPopupFactory = JBPopupFactory.getInstance();
        ListPopup dsPopup = jbPopupFactory.createListPopup(
                new BaseListPopupStep<>(
                        "Choose DataSource",
                        dataSourceNames,
                        iconList
                ) {
                    @Override
                    public @Nullable
                    PopupStep<?> onChosen(String selectedValue, boolean finalChoice) {
                        for (DbDataSource dataSource : dataSources) {
                            if (dataSource.getName().equals(selectedValue)) {
                                PsiElement psiElement = mybatisPsiElement.getPsiElement();
                                String fileName = psiElement.getContainingFile().getVirtualFile().getName();
                                if (!checkJdbcConsoleActive(fileName + ".sql")) {
                                    jdbcConsole = JdbcConsole
                                            .newConsole(project)
                                            .fromDataSource(dataSource)
                                            .forFile(getSqlFile(fileName))
                                            .build();
                                }
                                runSql(sql);
                                break;
                            }
                        }
                        return null;
                    }

                });
        dsPopup.showCenteredInCurrentWindow(project);
    }

    /**
     * 检查jdbcConsole存货
     * @param sqlFileName
     * @return
     */
    private boolean checkJdbcConsoleActive(String sqlFileName) {
        List<JdbcConsole> activeConsoles = JdbcConsole.getActiveConsoles(project);
        if (CollectionUtil.isNotEmpty(activeConsoles)) {
            if (StrUtil.isBlank(sqlFileName)) {
                this.jdbcConsole = activeConsoles.get(activeConsoles.size() - 1);
            } else {
                this.jdbcConsole = activeConsoles.stream()
                        .filter(s -> s.getVirtualFile().getName().equals(sqlFileName))
                        .findFirst()
                        .orElse(null);
            }
        }
        return Objects.nonNull(this.jdbcConsole);
    }

    private void runSql(String sql) {
        VirtualFile sqlFile = getSqlFile();

        DocumentUtils.writeSync(() -> {
            try {
                sqlFile.setBinaryContent(sql.getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {

            }
        });



        SqlScriptModel sqlScriptModel = new SqlScriptModel(project, sqlFile, null);

        this.jdbcConsole.executeQueries(editor, sqlScriptModel, new DatabaseSettings.ExecOption());
    }

    protected VirtualFile getSqlFile(){
        return getSqlFile("mybatis");
    }

    protected VirtualFile getSqlFile(String dataSourceName){
        LocalFileSystem localFileSystem = LocalFileSystem.getInstance();

        String projectBasePath = project.getBasePath();
        String path = projectBasePath + "/.idea/mybatis-runner";
        String sqlFileName = dataSourceName + ".sql";
        String sqlFilePath = path + "/" + sqlFileName;
        VirtualFile mybatisFile = localFileSystem.refreshAndFindFileByPath(sqlFilePath);
        if (Objects.nonNull(mybatisFile)){
            return mybatisFile;
        }

        try {
            File file = new File(sqlFilePath);
            FileUtils.forceMkdirParent(file);
            FileUtils.writeStringToFile(file,"", StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return getSqlFile(dataSourceName);
    }
}
